/*
Here's a small IPv4 example: it asks for a portbase and a destination and
starts sending packets to that destination.
*/
#include "RtpTransceiver.h"
#include "ConsoleLog.h"

#pragma warning(disable:4996)

void checkerror(int rtperr)
{
	if (rtperr < 0)
	{
		std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
		exit(-1);
	}
}

RtpTransceiver::RtpTransceiver(YMessageListInterface* pDecoder)
	: m_pMsg(nullptr)
{
	m_pSession = new MyRTPSession(pDecoder);
	m_pMsg = new YMessageList();
	m_pMsg->Init();
#ifdef RTP_SOCKETTYPE_WINSOCK
	WSADATA dat;
	WSAStartup(MAKEWORD(2, 2), &dat);
#endif // RTP_SOCKETTYPE_WINSOCK

	Init();
};

RtpTransceiver::~RtpTransceiver() {
	if (m_pMsg)
	{
		m_pMsg->Release();
		delete m_pMsg;
		m_pMsg = nullptr;
	}

	m_pSession->BYEDestroy(RTPTime(10, 0), 0, 0);
#ifdef RTP_SOCKETTYPE_WINSOCK
	WSACleanup();
#endif // RTP_SOCKETTYPE_WINSOCK
}

int RtpTransceiver::Init() {

	uint16_t portbase = 8080;
	uint16_t destport = 8080;
	uint32_t destip;
	std::string ipstr = "127.0.0.1";// "192.168.73.1";
	int status;

	std::cout << "Using version " << RTPLibraryVersion::GetVersion().GetVersionString() << std::endl;

	destip = inet_addr(ipstr.c_str());
	if (destip == INADDR_NONE)
	{
		std::cerr << "Bad IP address specified" << std::endl;
		return -1;
	}

	// The inet_addr function returns a value in network byte order, but
	// we need the IP address in host byte order, so we use a call to
	// ntohl
	destip = ntohl(destip);

	// Now, we'll create a RTP session, set the destination, send some
	// packets and poll for incoming data.

	RTPUDPv4TransmissionParams transparams;
	RTPSessionParams sessparams;

	// IMPORTANT: The local timestamp unit MUST be set, otherwise
	//            RTCP Sender Report info will be calculated wrong
	// In this case, we'll be sending 30 samples each second, so we'll
	// put the timestamp unit to (1.0/30.0)
	sessparams.SetOwnTimestampUnit(1 / 50);

	sessparams.SetAcceptOwnPackets(true);
	transparams.SetPortbase(portbase);
	status = m_pSession->Create(sessparams, &transparams);
	checkerror(status);

	RTPIPv4Address pdest_addr(destip, destport);

	status = m_pSession->AddDestination(pdest_addr);
	checkerror(status);

	m_pSession->SetDefaultPayloadType(96);
	m_pSession->SetDefaultMark(true);
	m_pSession->SetTimestampUnit(1 / 50);
	m_pSession->SetDefaultTimestampIncrement(1280*720*5/30);// bitrate/framerate

	return 0;
}

int RtpTransceiver::SendRtp(uint8_t * send_data, const size_t len)
{
	printf("Sending packet--len=%d\n", len);
	int status;

	char sendbuf[1430];   // send buffer
	memset(sendbuf, 0, 1430);

	if (len <= MAX_RTP_LEN)
	{
		// send the packet
		status = m_pSession->SendPacket((void *)send_data, len);
		if (status < 0)
		{
			printf("SendPacket error %s\n", RTPGetErrorString(status).c_str());
			return -1;
		}

		checkerror(status);

	}
	else if (len > MAX_RTP_LEN)
	{
		m_pSession->SetDefaultMark(false);
		int k = 0, l = 0;
		k = len / MAX_RTP_LEN;
		l = len % MAX_RTP_LEN;
		int index = 0;//index of pkt

		while (index < k || (index == k && l>0))
		{
			if ((0 == index) || (index<k && 0 != index))//except last pkt
			{
				memcpy(sendbuf, &send_data[index*MAX_RTP_LEN], MAX_RTP_LEN);
				status = m_pSession->SendPacket((void *)sendbuf, MAX_RTP_LEN);
				checkerror(status);
				index++;
			}
			//last pkt
			else if ((k == index && l>0) || (index == (k - 1) && l == 0))
			{
				//
				m_pSession->SetDefaultMark(true);

				int iSendLen;
				if (l > 0)
				{
					iSendLen = len - index * MAX_RTP_LEN;
				}
				else
					iSendLen = MAX_RTP_LEN;

				memcpy(sendbuf, &send_data[index*MAX_RTP_LEN], iSendLen);
				status = m_pSession->SendPacket((void *)sendbuf, iSendLen);

				checkerror(status);
				index++;
			}
		}
	}

	return 0;
}

void RtpTransceiver::SendMessage(uint8_t* data, const size_t len) {
	std::lock_guard<std::mutex> guard(m_mutex);
	m_pMsg->AddData(data, len);
}

void RtpTransceiver::ProcessMessage() {
	while (!m_bExit)
	{
		if (!m_pMsg->IsEmpty())
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			int len = m_pMsg->GetNextLength();
			uint8_t* data = new uint8_t[len];
			m_pMsg->GetData(data, len);
			SendRtp(data, len);
			delete[]data;
		}

#ifndef RTP_SUPPORT_THREAD
		int status = m_pSession->Poll();
		checkerror(status);
#endif // RTP_SUPPORT_THREAD
	}
}

RtpTransceiver::MyRTPSession::MyRTPSession(YMessageListInterface* pDecoder)
{
	m_pDecoder = pDecoder;

	m_videoData.pData = new uint8_t[MAX_VIDEO_BUF_SIZE];
	m_videoData.len = 0;
	/*const char* filename_send = "rtprecv.h264";
	int err = fopen_s(&file_recv, filename_send, "wb");
	if (err)
	{
		printf("Can not open file %s\n", filename_send);
		exit(-1);
	}*/
}

RtpTransceiver::MyRTPSession::~MyRTPSession()
{
	if (!m_videoData.pData)
	{
		delete[]m_videoData.pData;
		m_videoData.pData = nullptr;
	}
	//fclose(file_recv);
}

void RtpTransceiver::MyRTPSession::OnValidatedRTPPacket(RTPSourceData *srcdat, RTPPacket *rtppack, bool isonprobation, bool *ispackethandled)
{
	//printf("Got packet in OnValidatedRTPPacket from source 0x%04x!\n", srcdat->GetSSRC());
	int npayload = rtppack->GetPayloadLength();
	uint8_t* payload = rtppack->GetPayloadData();
	uint32_t ts = rtppack->GetTimestamp();
	if (rtppack->HasMarker())//last pkt
	{
		memcpy(m_videoData.pData + m_videoData.len, payload, npayload);
		m_videoData.len += npayload;
		m_pDecoder->SendMessage(m_videoData.pData, m_videoData.len);

		//YLOG("one nalu received========len=%d\n", m_videoData.len);
		memset(m_videoData.pData, 0, m_videoData.len);//clear buffer
		m_videoData.len = 0;
	}
	else//copy to buffer
	{
		memcpy(m_videoData.pData + m_videoData.len, payload, npayload);
		m_videoData.len += npayload;
	}
	//fwrite(rtppack->GetPayloadData(), 1, rtppack->GetPayloadLength(), file_recv);

	YLOG("timestamp=%d\n", ts);
	*ispackethandled = true;
}